/**
 * File: GenericMetaStore.java
 * Created by: mhaimel
 * Created on: Jun 11, 2010
 * CVS:  $Id: GenericMetaStore.java 1.0 Jun 11, 2010 4:29:21 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.utils.data.store;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import uk.ac.ebi.curtain.utils.concurrent.UtilsCollect;

/**
 * @author mhaimel
 *
 */
public abstract class GenericMetaStore<T> implements SequenceMetaStore<T> {
	private Log log = LogFactory.getLog(this.getClass());
	private final ConcurrentMap<Integer, Collection<T[]>> dataIdx = UtilsCollect.newConcurrentMap();
	private final ConcurrentMap<Integer, String []> metaIdx = UtilsCollect.newConcurrentMap();
	
	@Override
	public void addEntry(Integer id, T ... dataSet) throws IllegalArgumentException {
		if(dataSet.length < 1){
			throw new IllegalArgumentException("Dataset provided is empty!!!");
		}
		Collection<T[]> idx = dataIdx.get(id);
		if(null == idx){
			throw new IllegalArgumentException("Set with Id not registered: " + id);
		}
		idx.add(dataSet);
	};

	@Override
	public void createSet(Integer id, String... annotation)  throws IllegalArgumentException {
		String[] tmpAnno = metaIdx.get(id);
		if(null != tmpAnno){
			throw new IllegalArgumentException("Set id already registered: " + id);
		}
		if(annotation.length < 1){
			throw new IllegalArgumentException("No Annotations provided for set Id: " + id);
		}
		metaIdx.put(id, annotation);
		dataIdx.put(id, new LinkedBlockingQueue<T[]>());
	}

	@Override
	public String[] getAnnotation(Integer id) {
		return metaIdx.get(id);
	}

	@Override
	public Collection<T[]> getEntries(Integer id) {
		Collection<? extends T[]> coll = dataIdx.get(id);
		if(null == coll){
			return null;
		} else {
			return Collections.unmodifiableCollection(coll);
		}
	}

	@Override
	public Set<Integer> getSetIds() {
		return Collections.unmodifiableSet(metaIdx.keySet());
	}

	@Override
	public void load(File propertyFile) {
		try {
			Configuration config = new PropertiesConfiguration(propertyFile);
			List<String> idList = config.getList("store.id");
			for(String sid : idList){
				Integer id = Integer.valueOf(sid);
				String subKey = "store."+sid;
//				Configuration subset = config.subset(subKey);
				List<String> typeList = config.getList(subKey+".type");
				String[] typeArr = typeList.toArray(new String[0]);
				this.createSet(id, typeArr);
				
				List<String> dataList = config.getList(subKey+".data");
				for(String data : dataList){
					data = data.trim();
					String[] split = StringUtils.split(data, ' ');

					List<T> tlist = new ArrayList<T>();
					for(String s : split){
						T t = _stringToType(s);
						if(null != t){
							tlist.add(t);
						}
					}
					this.addEntry(id,  _toArray(tlist));
				}
			}
		} catch (ConfigurationException e) {
			e.printStackTrace();
		}
	}

	protected abstract T[] _toArray(List<T> tlist);

	protected abstract T _stringToType(String string);
}
